/*
 * MIT License
 *
 * Copyright (c) 2023 北京凯特伟业科技有限公司
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package com.je.meta.service.datasource.impl;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.je.common.base.DynaBean;
import com.je.common.base.db.DbFieldVo;
import com.je.common.base.entity.extjs.Model;
import com.je.common.base.exception.APIWarnException;
import com.je.common.base.exception.PlatformException;
import com.je.common.base.exception.PlatformExceptionEnum;
import com.je.common.base.service.*;
import com.je.common.base.service.rpc.BeanService;
import com.je.common.base.service.rpc.CommonTableRpcService;
import com.je.common.base.spring.SpringContextHolder;
import com.je.common.base.table.service.BuildingSqlService;
import com.je.common.base.util.*;
import com.je.core.entity.extjs.JSONTreeNode;
import com.je.ibatis.extension.conditions.ConditionsWrapper;
import com.je.meta.constant.DataSourceTypeCons;
import com.je.meta.model.view.QueryConfigVo;
import com.je.meta.model.view.ViewColumn;
import com.je.meta.model.view.ViewDdlVo;
import com.je.meta.model.view.ViewOuput;
import com.je.meta.service.datasource.DataSourceExecuteService;
import com.je.meta.service.datasource.DataSourceService;
import com.je.meta.service.table.MetaViewService;
import com.je.meta.util.enumUtil.DataSourceTypeEnum;
import com.je.servicecomb.RpcSchemaFactory;
import org.apache.commons.collections.map.HashedMap;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;


import java.sql.*;
import java.util.*;

import static com.je.servicecomb.JECloud.PRODUCT_CORE_META;


@Service
public class DataSourceServiceImpl  implements DataSourceService {

    @Autowired
    private MetaService metaService;
    @Autowired
    private CommonService commonService;
    @Autowired
    private PcDbSQLService pcDbSQLService;
    @Autowired
    private MetaViewService metaViewService;
    @Autowired
    private QueryBuilderService queryBuilderService;
    @Qualifier("buildingMySqlServiceImpl")
    @Autowired
    private BuildingSqlService buildingSqlService;

    @Override
    public void doCopy(DynaBean dynaBean) {
        DynaBean target = metaService.selectOneByPk("JE_CORE_DATASOURCE",dynaBean.getStr("targetId"));
        DynaBean parent = metaService.selectOneByPk("JE_CORE_DATASOURCE",dynaBean.getStr("SY_PARENT"));

        target.setStr("DATASOURCE_TEXT",dynaBean.getStr("DATASOURCE_TEXT"));
        target.setStr("DATASOURCE_CODE",dynaBean.getStr("DATASOURCE_CODE"));
        target.setStr("SY_PARENTPATH",parent.getStr("SY_PATH"));
        target.setStr("SY_PARENT",dynaBean.getStr("SY_PARENT"));
        String JE_CORE_DATASOURCE_ID = JEUUID.uuid();
        target.setStr("JE_CORE_DATASOURCE_ID",JE_CORE_DATASOURCE_ID);
        target.setStr("SY_PATH",parent.getStr("SY_PATH")+"/"+JE_CORE_DATASOURCE_ID);
        commonService.generateTreeOrderIndex(target);
        commonService.buildModelCreateInfo(target);
        metaService.insert(target);
    }

    @Override
    public List<Model> getSelectModel(String sql) {
        return pcDbSQLService.selectModel(sql);
    }

    @Override
    public JSONTreeNode getDsTree(String chartId) {
        DynaBean chart = metaService.selectOneByPk("JE_CORE_CHARTS",chartId);
        String ids = chart.getStr("CHARTS_DSIDS");
        if(StringUtil.isEmpty(ids)){
            return null;
        }

        List<DynaBean> dataSource = metaService.select("JE_CORE_DATASOURCE", ConditionsWrapper.builder().in("JE_CORE_DATASOURCE_ID", Arrays.asList(ids.toString().split(","))));
        JSONTreeNode dataSourceRootNode = buildDataSourceTree(dataSource);
        for(JSONTreeNode jsonTreeNode:dataSourceRootNode.getChildren()){
            JSONTreeNode fieldTree =  buildFieldTree(jsonTreeNode.getBean());
            JSONTreeNode parameterTree =  buildParameterTree(jsonTreeNode.getBean());
            List<JSONTreeNode> nodeList = new ArrayList<>();
            nodeList.add(fieldTree);
            nodeList.add(parameterTree);
            jsonTreeNode.setChildren(nodeList);
        }
        return dataSourceRootNode;
    }

    @Override
    public String getSelectDdl(String resourceId) {
       ConditionsWrapper conditionsWrapper = ConditionsWrapper.builder();
        List<DynaBean> columns = metaService.select("JE_CORE_TABLECOLUMN",conditionsWrapper.eq("TABLECOLUMN_RESOURCETABLE_ID",resourceId)
                .eq("TABLECOLUMN_ISCREATE","1").orderByAsc("TABLECOLUMN_CLASSIFY"));
        String tableCode = columns.get(0).getStr("TABLECOLUMN_TABLECODE");
        String  ddl = " SELECT {0} FROM {1}";
        String columnStr =  getColumnStr(columns,"codeAsCn");
        return StringUtil.format(ddl,columnStr,tableCode);
    }

    private String getColumnStr(List<DynaBean> columns,String type) {
        StringBuffer stringBuffer = new StringBuffer();
        for(int i = 0;i<columns.size();i++){
            DynaBean column = columns.get(i);
            String code = column.getStr("TABLECOLUMN_CODE");
            if(StringUtil.isEmpty(code)){
                continue;
            }
            String text = column.getStr("TABLECOLUMN_NAME");
            if(StringUtil.isEmpty(text)){
                text =code;
            }
            if("codeAsCn".equals(type)){
                if(i==columns.size()-1){
                    stringBuffer.append(code+" AS "+text);
                }else {
                    stringBuffer.append(code+" AS "+text+",");
                }
            }else if("code".equals(type)){
                if(i==columns.size()-1){
                    stringBuffer.append(code);
                }else {
                    stringBuffer.append(code+",");
                }
            }else {
                if(i==columns.size()-1){
                    stringBuffer.append(text);
                }else {
                    stringBuffer.append(text+",");
                }
            }

        }
        return stringBuffer.toString();
    }

    public StringBuilder getColumnDdl(List<ViewOuput> ouputListList, String masterTable) {
        StringBuilder ddl = new StringBuilder();
        ddl.append("SELECT ");
        for (int i = 0, size = ouputListList.size(); i < size; i++) {
            ViewOuput column = ouputListList.get(i);
            String formula = column.getFormula();
            String tableCode = column.getTableCode();
            String columnCode = column.getColumn();
            String name = column.getName();
            String value = column.getValue();
            String asSql = "";
            //公式
            if (!(StringUtil.isEmpty(formula))) {
                String chSql = formula + String.format("(%s %s)", value, asSql) + " AS " + name;
                ddl.append(chSql);
            } else {
                String chSql = value + " AS " + name;
                ddl.append(chSql);
            }

            if (size - 1 != i) {
                ddl.append(", ");
            }
        }
        ddl.append(" FROM " + masterTable);
        return ddl;
    }

    @Override
    public String getSelectDdlByConfig(String type, ViewDdlVo viewDdlVo) {
        if(DataSourceTypeCons.VIEW.equals(type)){
            String ddl = getViewSelectDdlByConfig(viewDdlVo,null);
            QueryConfigVo queryConfigVo =viewDdlVo.getQueryConfigVo();
            if(queryConfigVo!=null){
                JSONObject jsonObject = new JSONObject();
                jsonObject.put("startTime",queryConfigVo.getStartTime());
                jsonObject.put("endTime",queryConfigVo.formatTime(DateUtils.getNow()));
                ddl = queryBuilderService.formatSqlParameter(jsonObject,ddl);
            }
            return ddl;
        }
        if(DataSourceTypeCons.TABLE.equals(type)){
            String ddl = getTableSelectDdlByConfig(viewDdlVo.getQueryConfigVo(),null,"codeAsCn");
            if(viewDdlVo.getQueryConfigVo()!=null){
                JSONObject jsonObject = new JSONObject();
                jsonObject.put("startTime",viewDdlVo.getQueryConfigVo().getStartTime());
                jsonObject.put("endTime",viewDdlVo.getQueryConfigVo().formatTime(DateUtils.getNow()));
                ddl = queryBuilderService.formatSqlParameter(jsonObject,ddl);
            }
            return ddl;
        }
        
        return null;
    }

    private String getTableSelectDdlByConfig(QueryConfigVo queryConfigVo,JSONObject parameterJson,String type) {
        DynaBean dynaBean = new DynaBean();
        String tableCode = queryConfigVo.getTableCode();
        dynaBean.setStr(BeanService.KEY_TABLE_CODE,tableCode);
        dynaBean.setStr(BeanService.DEF_ALL_FIELDS,getFieldsByTableCode(tableCode,type));
        dynaBean.setStr(BeanService.KEY_WHERE,buildWhereSqlByConfig(queryConfigVo,parameterJson));
        String order = queryConfigVo.getOrderBy();
        if(StringUtil.isNotEmpty(order)){
            dynaBean.setStr(BeanService.KEY_ORDER,order);
        }
        String sql = buildingSqlService.getSelectOneByWhereSql(dynaBean);
        if(queryConfigVo.getTotalSize()>0){
            sql+=" LIMIT "+queryConfigVo.getTotalSize();
        }
        return sql;
    }

    private String getFieldsByTableCode(String tableCode,String type) {
        List<DynaBean> columns = metaService.select("JE_CORE_TABLECOLUMN",ConditionsWrapper.builder().eq("TABLECOLUMN_TABLECODE",tableCode)
                .eq("TABLECOLUMN_ISCREATE","1").orderByAsc("TABLECOLUMN_CLASSIFY"));
        return getColumnStr(columns,type);
    }

    private String getViewSelectDdlByConfig(ViewDdlVo viewDdlVo,JSONObject parameterJson) {
        String tableId = viewDdlVo.getMasterTableId();
        DynaBean resource = metaService.selectOneByPk("JE_CORE_RESOURCETABLE",tableId);
        String masterTable = resource.getStr("RESOURCETABLE_TABLECODE");
        List<String> tableList = metaViewService.getTableList(viewDdlVo.getViewOuput(),masterTable);
        StringBuilder columnDdl = getColumnDdl(viewDdlVo.getViewOuput(), masterTable);
        StringBuilder groupDdl = metaViewService.getGroupDdl(viewDdlVo.getViewOuput());
        String orderDdl = getOrderDdl(viewDdlVo.getViewOuput()).toString();
        Map<String, StringBuilder> joinMap;
        if(viewDdlVo.getViewColumn()!=null&&viewDdlVo.getViewColumn().size()>0){
            joinMap = metaViewService.getJoinDdl(viewDdlVo.getViewColumn(), masterTable);
        }else{
            joinMap = new HashedMap();
        }

        QueryConfigVo queryConfigVo = viewDdlVo.getQueryConfigVo();
        String whereSql ="";
        //构建ddl where
        if(queryConfigVo!=null){
            if(StringUtil.isEmpty(queryConfigVo.getBaseFieldTableCode())){
                queryConfigVo.setBaseFieldTableCode(resource.getStr("RESOURCETABLE_TABLECODE"));
            }
            whereSql = buildWhereSqlByConfig(queryConfigVo,parameterJson);
        }
        orderDdl = buildOrderSqlByConfig(queryConfigVo,orderDdl);
        StringBuilder ddl = new StringBuilder();
        ddl.append(columnDdl);
        boolean isJoin =false;
        if("1".equals(joinMap.get("isJoin")==null?"":joinMap.get("isJoin").toString())){
            isJoin=true;
        }
        joinMap.remove("isJoin");
        if (isJoin) {
            StringBuilder joinDdl = new StringBuilder("");
            StringBuilder andDdl = new StringBuilder("");
            for (String key : joinMap.keySet()) {
                if (key.contains("and")) {
                    andDdl.append(joinMap.get(key));
                } else {
                    joinDdl.append(joinMap.get(key));
                }
            }
            ddl.append(joinDdl);
            ddl.append(andDdl);
            ddl.append(whereSql);
            ddl.append(groupDdl);
            ddl.append(" "+orderDdl);
        }else{
            for (String childrenTable : tableList) {
                ddl.append("," + childrenTable);
            }
            if (joinMap.size() > 0) {
                for (String key : joinMap.keySet()) {
                    if("0".equals(joinMap.get(key).toString())||"1".equals(joinMap.get(key).toString())){
                        continue;
                    }
                    ddl.append(joinMap.get(key));
                }
            } else {
                ddl.append(" WHERE 1=1");
            }
            if(!ddl.toString().contains(" WHERE ")){
                ddl.append(" WHERE 1=1");
            }
            ddl.append(whereSql);
            ddl.append(groupDdl);
            ddl.append(" "+orderDdl);
        }
        if(queryConfigVo.getTotalSize()>0){
            ddl.append( " LIMIT "+queryConfigVo.getTotalSize());
        }
        return ddl.toString();
    }

    public StringBuilder getOrderDdl(List<ViewOuput> ouputListList) {
        StringBuilder ddl = new StringBuilder();
        boolean flag = false;
        for (int i = 0, size = ouputListList.size(); i < size; i++) {
            ViewOuput column = ouputListList.get(i);
            String whereColumn = column.getColumn();
            String tableCode = column.getTableCode();
            String name = column.getName();
            String formula =  column.getFormula();
            String sort = column.getSort();
            String value = column.getValue();
            if (!(StringUtil.isEmpty(sort))) {
                if (!flag) {
                    ddl.append(" ORDER BY ");
                    flag = true;
                }
                if(StringUtil.isNotEmpty(formula)){
                    //数据源视图
                    ddl.append(name + " " + sort);
                }else{
                    ddl.append(value + " " + sort);
                }
                if (flag) {
                    ddl.append(" ,");
                }
            }
        }
        String sortDdl = ddl.toString();
        if (!StringUtil.isEmpty(sortDdl)) {
            sortDdl = sortDdl.substring(0, sortDdl.length() - 1);
        }
        return new StringBuilder(sortDdl);
    }

    @Override
    public List<Map<String, Object>> execute(String config,String id, String parameterStr,String limit) {
        DynaBean datasource = metaService.selectOneByPk("JE_CORE_DATASOURCE",id);
        String type =datasource.getStr("DATASOURCE_TYPE");
        if("JS".equals(type)){
            return null;
        }
        JSONObject parameterJson = strToJson(parameterStr);
        if(StringUtil.isNotEmpty(config)){
            buildDataSourceInfoByConfig(config,datasource,parameterJson);
        }else{
            buildDataSourceInfoById(datasource,parameterJson);
        }
        DataSourceExecuteService dataSourceExecuteService = SpringContextHolder.getBean(DataSourceTypeEnum.valueOf(type).getServiceName());
        return dataSourceExecuteService.execute(datasource,parameterStr,limit);
    }

    public JSONObject strToJson(String parameterStr){
        JSONObject parameterJson = new JSONObject();
        if(StringUtil.isNotEmpty(parameterStr)){
            parameterJson = JSON.parseObject(parameterStr);
            //去除空值的key
            if(parameterJson!=null){
                Iterator<String> sIterator = parameterJson.keySet().iterator();
                while(sIterator.hasNext()){
                    String key = sIterator.next();
                    String value = parameterJson.getString(key);
                    if(StringUtil.isEmpty(value)){
                        sIterator.remove();
                    }
                }
            }
        }
        return parameterJson;
    }

    private void buildDataSourceInfoById(DynaBean datasource, JSONObject parameterJson) {
        String type =datasource.getStr("DATASOURCE_TYPE");
        String ddl = datasource.getStr("DATASOURCE_DATA");

        if(DataSourceTypeCons.VIEW.equals(type) || DataSourceTypeCons.TABLE.equals(type) ){
            //获取配置信息，得到QueryConfigVo queryConfigVo
            QueryConfigVo queryConfigVo = JSON.parseObject(datasource.getStr("DATASOURCE_CONFIG"),QueryConfigVo.class);
            //替换全局变量
            if(queryConfigVo!=null){
                parameterJson.put("startTime",queryConfigVo.getStartTime());
                parameterJson.put("endTime",queryConfigVo.formatTime(DateUtils.getNow()));
            }
            ddl = queryBuilderService.formatSqlParameter(parameterJson, ddl);
            datasource.setStr("DATASOURCE_DATA", ddl);
        }else if( DataSourceTypeCons.SQL.equals(type)){
            ddl = queryBuilderService.formatSqlParameter(parameterJson, ddl);
            datasource.setStr("DATASOURCE_DATA", ddl);
        }
    }

    private void buildDataSourceInfoByConfig(String config, DynaBean datasource, JSONObject parameterJson) {
        String type =datasource.getStr("DATASOURCE_TYPE");
        if(DataSourceTypeCons.VIEW.equals(type)){
            ViewDdlVo viewDdlVo =JSON.parseObject(config,ViewDdlVo.class);
            QueryConfigVo queryConfigVo = viewDdlVo.getQueryConfigVo();
            String ddl = getViewSelectDdlByConfig(viewDdlVo,parameterJson);
            //替换全局变量
            if(queryConfigVo!=null){
                parameterJson.put("startTime",queryConfigVo.getStartTime());
                parameterJson.put("endTime",queryConfigVo.formatTime(DateUtils.getNow()));
            }
            ddl = queryBuilderService.formatSqlParameter(parameterJson,ddl);
            datasource.setStr("DATASOURCE_DATA",ddl);
        }else  if(DataSourceTypeCons.TABLE.equals(type)){
            ViewDdlVo viewDdlVo =JSON.parseObject(config,ViewDdlVo.class);
            QueryConfigVo queryConfigVo = viewDdlVo.getQueryConfigVo();
            String ddl = getTableSelectDdlByConfig(queryConfigVo,parameterJson,"codeAsCn");
            //替换全局变量
            if(queryConfigVo!=null){
                parameterJson.put("startTime",queryConfigVo.getStartTime());
                parameterJson.put("endTime",queryConfigVo.formatTime(DateUtils.getNow()));
            }
            ddl = queryBuilderService.formatSqlParameter(parameterJson,ddl);
            datasource.setStr("DATASOURCE_DATA",ddl);
        }else if(DataSourceTypeCons.SERVICE.equals(type)){
            datasource.setStr("DATASOURCE_CONFIG",config);
        }else if(DataSourceTypeCons.ACTION.equals(type)){
            datasource.setStr("DATASOURCE_CONFIG",config);
        }else if(DataSourceTypeCons.SQL.equals(type)){
            String  ddl =queryBuilderService.formatSqlParameter(parameterJson,datasource.getStr("DATASOURCE_DATA"));
            datasource.setStr("DATASOURCE_DATA",ddl);
        }
    }


    @Override
    public JSONObject batchExecute(String strData) {
        JSONObject result = new JSONObject();
        JSONArray jsonArray = JSON.parseArray(strData);
        if(jsonArray!=null&&jsonArray.size()>0){
            for(int i =0;i<jsonArray.size();i++){
                JSONObject jsonObject = jsonArray.getJSONObject(i);
                String datasourceId = jsonObject.getString("JE_CORE_DATASOURCE_ID");
                DynaBean datasource = metaService.selectOneByPk("JE_CORE_DATASOURCE",datasourceId);

                String parameterStr = jsonObject.getString("parameterStr");
                String limit = jsonObject.getString("limit");
                List<Map<String, Object>> list =execute(null,datasourceId,parameterStr,limit);
                JSONObject item = new JSONObject();
                item.put("type",datasource.getStr("DATASOURCE_TYPE"));
                item.put("config",datasource.getStr("DATASOURCE_CONFIG"));
                item.put("data",list);
                result.put(datasource.getStr("DATASOURCE_CODE"),item);
            }
        }
        return result;
    }

    @Override
    public void doUpdate(DynaBean dynaBean) {
        String type = dynaBean.getStr("DATASOURCE_TYPE");
        if(DataSourceTypeCons.VIEW.equals(type)){
            ViewDdlVo viewDdlVo = new ViewDdlVo();
            viewDdlVo.setMasterTableId(dynaBean.getStr("masterTableId"));
            List<ViewColumn> viewColumn = JSON.parseArray(dynaBean.getStr("DATASOURCE_INCIDENCE_RELATION"),ViewColumn.class);
            List<ViewOuput> viewOuput = JSON.parseArray(dynaBean.getStr("DATASOURCE_OUTPUT_COLUMNS"),ViewOuput.class);
            QueryConfigVo queryConfigVo = JSON.parseObject(dynaBean.getStr("DATASOURCE_CONFIG"),QueryConfigVo.class);
            viewDdlVo.setViewColumn(viewColumn);
            viewDdlVo.setViewOuput(viewOuput);
            viewDdlVo.setQueryConfigVo(queryConfigVo==null?new QueryConfigVo():queryConfigVo);
            if(viewOuput!=null&&viewOuput.size()>0&&StringUtil.isNotEmpty(viewDdlVo.getMasterTableId())){
                String sql = getViewSelectDdlByConfig(viewDdlVo,null);
                dynaBean.setStr("DATASOURCE_DATA",sql);
                dynaBean.set("DATASOURCE_RESULT_CONFIG",buildViewResultConfig(dynaBean,viewDdlVo));
            }
        }else  if(DataSourceTypeCons.TABLE.equals(type)){
            QueryConfigVo queryConfigVo = JSON.parseObject(dynaBean.getStr("DATASOURCE_CONFIG"),QueryConfigVo.class);
            if(queryConfigVo!=null){
                if(StringUtil.isEmpty(queryConfigVo.getTableCode())){
                    throw new PlatformException(MessageUtils.getMessage("dataSource.tableCode.notEmpty"), PlatformExceptionEnum.UNKOWN_ERROR);
                }
                String sql = getTableSelectDdlByConfig(queryConfigVo,null,"codeAsCn");
                //sql 不包含查询条件
                dynaBean.setStr("DATASOURCE_DATA",sql);
            }
            dynaBean.setStr("DATASOURCE_RESULT_CONFIG",buildTableResultConfig(dynaBean.getStr("DATASOURCE_CONFIG")));

        }else if(DataSourceTypeCons.SERVICE.equals(type)&&StringUtil.isNotEmpty(dynaBean.getStr("DATASOURCE_CONFIG"))){
            dynaBean.setStr("DATASOURCE_RESULT_CONFIG",buildActionResultConfig(dynaBean.getStr("DATASOURCE_CONFIG")));
        }else if(DataSourceTypeCons.ACTION.equals(type)){
            dynaBean.setStr("DATASOURCE_RESULT_CONFIG",buildActionResultConfig(dynaBean.getStr("DATASOURCE_CONFIG")));
        }else if(DataSourceTypeCons.SQL.equals(type)&&StringUtil.isNotEmpty(dynaBean.getStr("DATASOURCE_DATA"))){
            DynaBean product = metaService.selectOneByPk("JE_PRODUCT_MANAGE",dynaBean.getStr("SY_PRODUCT_ID"));
            dynaBean.setStr("DATASOURCE_RESULT_CONFIG",buildSqlResultConfig(dynaBean.getStr("DATASOURCE_DATA"),product.getStr("PRODUCT_CODE")));
        }
        commonService.buildModelModifyInfo(dynaBean);
        metaService.update(dynaBean);
    }

    private String buildTableResultConfig(String config) {
        QueryConfigVo queryConfigVo = JSONObject.parseObject(config,QueryConfigVo.class);
        JSONObject jsonObject = new JSONObject();
        String params = queryConfigVo.getParameterByJquery(queryConfigVo.getEditorFn());
        if(StringUtil.isEmpty(params)){
            params = queryConfigVo.getParameterByJquery(queryConfigVo.getQueryFn());
        }
        jsonObject.put("params",params);
        jsonObject.put("fields",getFieldsByTableCode(queryConfigVo.getTableCode(),"cn"));
        return jsonObject.toJSONString();
    }

    private String buildSqlResultConfig(String sql,String productCode) {
        JSONObject jsonObject = new JSONObject();
        String fields = getSqlFields(sql,productCode);
        jsonObject.put("fields",fields);
        String parameter = getSqlParameter(sql);
        if(StringUtil.isNotEmpty(parameter)){
            JSONArray jsonArray = new JSONArray();
            for(String str:parameter.split(",")){
                JSONObject parameterJson = new JSONObject();
                parameterJson.put("name",str);
                jsonArray.add(parameterJson);
            }
            jsonObject.put("params",jsonArray);
        }
        return jsonObject.toJSONString();
    }

    private String getSqlParameter(String sql) {
        sql = sql.toUpperCase();
        if(!sql.contains("{")){
            return null;
        }
        sql = sql.replaceAll("(\\\r\\\n|\\\r|\\\n|\\\n\\\r|\\\t)", " ");
        sql = sql;
        int index = sql.indexOf(" WHERE ");
        sql = sql.substring(index);
        String parameter="";
        while (sql.contains("{")){
           int left = sql.indexOf("{");
           int right = sql.indexOf("}");
           String field = sql.substring(left+1,right);
           parameter+=field+",";
           sql = sql.replaceFirst("\\{"," ");
            sql = sql.replaceFirst("}"," ");
        }
        if(StringUtil.isNotEmpty(parameter)){
            parameter = parameter.substring(0,parameter.length()-1);
        }
        return parameter;
    }

    private String buildActionResultConfig(String config) {
        JSONObject jsonObject =  JSON.parseObject(config);
        String fieldName = jsonObject.getString("fieldName");
        String paramName = jsonObject.getString("paramName");
        JSONObject resultConfig = new JSONObject();
        resultConfig.put("fields",fieldName);
        if(StringUtil.isNotEmpty(paramName)){
            JSONArray jsonArray = new JSONArray();
            for(String str:paramName.split(",")){
                JSONObject parameter = new JSONObject();
                parameter.put("name",str);
                jsonArray.add(parameter);
            }
            resultConfig.put("params",jsonArray.toJSONString());
        }
        return resultConfig.toJSONString();
    }

    private String buildViewResultConfig(DynaBean dataSource, ViewDdlVo viewDdlVo) {
        JSONObject jsonObject = new JSONObject();
        List<ViewOuput> viewOuputs = viewDdlVo.getViewOuput();
        String fields ="";
        for(int i =0;i<viewOuputs.size();i++){
            ViewOuput viewOuput = viewOuputs.get(i);
            if(i==viewOuputs.size()-1){
                fields+=viewOuput.getName();
            }else{
                fields+=viewOuput.getName()+",";
            }
        }
        QueryConfigVo queryConfigVo = viewDdlVo.getQueryConfigVo();
        String params = queryConfigVo.getParameterByJquery(queryConfigVo.getEditorFn());
        if(StringUtil.isEmpty(params)){
            params = queryConfigVo.getParameterByJquery(queryConfigVo.getQueryFn());
        }
        jsonObject.put("params",params);
        jsonObject.put("fields",fields);
        return jsonObject.toJSONString();
    }

    @Override
    public String getFieldsBySql(String id,String tableCode) {
        DynaBean dynaBean = metaService.selectOneByPk("JE_CORE_DATASOURCE",id);
        String type = dynaBean.getStr("DATASOURCE_TYPE");
        String fields = "";
        if(DataSourceTypeCons.VIEW.equals(type)){
            List<ViewOuput> viewOuputList = JSON.parseArray(dynaBean.getStr("DATASOURCE_OUTPUT_COLUMNS"),ViewOuput.class);
            for(int i =0;i<viewOuputList.size();i++){
                if(i==viewOuputList.size()-1){
                    fields+= viewOuputList.get(i).getName();
                }else{
                    fields+=viewOuputList.get(i).getName()+",";
                }
            }
        }else  if(DataSourceTypeCons.TABLE.equals(type)){
            fields =  getFieldsByTableCode(tableCode,"cn");
        }else if(DataSourceTypeCons.SQL.equals(type)){
            String sql = dynaBean.getStr("DATASOURCE_DATA");
            fields = getSqlFields(sql,dynaBean.getStr("SY_PRODUCT_CODE"));
        }else if(DataSourceTypeCons.SERVICE.equals(type)){
           String config = dynaBean.getStr("DATASOURCE_CONFIG");
           JSONObject jsonObject = JSON.parseObject(config);
           if(jsonObject!=null){
               fields = jsonObject.getString("fieldName");
           }
        }else if(DataSourceTypeCons.ACTION.equals(type)){
            String config = dynaBean.getStr("DATASOURCE_CONFIG");
            JSONObject jsonObject = JSON.parseObject(config);
            if(jsonObject!=null){
                fields = jsonObject.getString("fieldName");
            }
        }
        return fields;
    }

    @Override
    public List<JSONTreeNode> getPreAddDataSource(String dataSourceIds) {
        List<JSONTreeNode> list = new ArrayList<>();
        String[] idArr = dataSourceIds.split(",");
        for(String dataSourceId:idArr){
            DynaBean dataSource = metaService.selectOneByPk("JE_CORE_DATASOURCE",dataSourceId);
            JSONTreeNode node = buildDataSourceTreeNode("ROOT",dataSource);
            JSONTreeNode fieldTree =  buildFieldTree(node.getBean());
            JSONTreeNode parameterTree =  buildParameterTree(node.getBean());
            List<JSONTreeNode> nodeList = new ArrayList<>();
            nodeList.add(fieldTree);
            nodeList.add(parameterTree);
            node.setChildren(nodeList);
            list.add(node);
        }
        return list;
    }

    @Override
    public JSONObject getDataSourceParameter(String ids) {
         List<DynaBean> list = metaService.select("JE_CORE_DATASOURCE",ConditionsWrapper.builder()
                 .in("JE_CORE_DATASOURCE_ID",Arrays.asList(ids.split(","))));
         JSONObject jsonObject = new JSONObject();
         for(DynaBean dynaBean:list){
             String resultConfig = dynaBean.getStr("DATASOURCE_RESULT_CONFIG");
             String code = dynaBean.getStr("DATASOURCE_CODE");
             String parameter =getParameterByResultConfig(resultConfig);
             jsonObject.put(code,parameter);
         }
        return jsonObject;
    }

    @Override
    public List<DynaBean> executeForRpc(String dataSourceCode, Map<String, Object> map, int limit) {
        DynaBean dynaBean = metaService.selectOne("JE_CORE_DATASOURCE",
                ConditionsWrapper.builder().eq("DATASOURCE_CODE",dataSourceCode));
        if(dynaBean==null ){
            return null;
        }
        String type = dynaBean.getStr("DATASOURCE_TYPE");
        JSONObject jsonObject =null;
        if(map!=null&&map.size()>0){
             jsonObject =strToJson(JSON.toJSONString(map));
        }else{
            jsonObject = new JSONObject();
        }
        if(DataSourceTypeCons.TABLE.equals(type)){
            String config = dynaBean.getStr("DATASOURCE_CONFIG");
            buildDataSourceInfoByConfigForRpc(config,dynaBean,jsonObject);
        }else{
            buildDataSourceInfoById(dynaBean,jsonObject);
        }

        DataSourceExecuteService dataSourceExecuteService = SpringContextHolder.getBean(DataSourceTypeEnum.valueOf(type).getServiceName());
        return dataSourceExecuteService.executeForRpc(dynaBean,map,limit);
    }

    private void buildDataSourceInfoByConfigForRpc(String config, DynaBean datasource, JSONObject parameterJson) {
        QueryConfigVo queryConfigVo =JSON.parseObject(config,QueryConfigVo.class);
        String ddl = getTableSelectDdlByConfig(queryConfigVo,parameterJson,"code");
        //替换全局变量
        if(queryConfigVo!=null){
            parameterJson.put("startTime",queryConfigVo.getStartTime());
            parameterJson.put("endTime",queryConfigVo.formatTime(DateUtils.getNow()));
        }
        ddl = queryBuilderService.formatSqlParameter(parameterJson,ddl);
        datasource.setStr("DATASOURCE_DATA",ddl);
    }

    private String getParameterByResultConfig(String resultConfig) {
        if(StringUtil.isEmpty(resultConfig)){
            return null;
        }
        JSONObject jsonObject = JSON.parseObject(resultConfig);
        if(jsonObject.containsKey("params")){
            return jsonObject.getString("params");
        }
        return null;
    }

    private String getSqlFields(String sql,String productCode) {
        ResultSetMetaData data=null;
        String fields="";
        if(!PRODUCT_CORE_META.equals(productCode)){
            CommonTableRpcService commonTableRpcService = RpcSchemaFactory.getRemoteProvierClazz(productCode,
                    "commonTableRpcService", CommonTableRpcService.class);
            fields = commonTableRpcService.getColumns(sql);
            return fields;
        }else{
            List<DbFieldVo> fieldVos = new ArrayList<DbFieldVo>();
            Connection connection = null;
            CallableStatement proc = null;
            ResultSet resultSet = null;
            connection = metaService.getConnection();
            try {
                proc = connection.prepareCall(sql);
                DbProduceUtil.registerParams(proc, fieldVos);
                proc.execute();
                resultSet = proc.getResultSet();
                data = resultSet.getMetaData();
                int count = 0;
                count = data.getColumnCount();
                for (int i = 1; i <= count; i++) {
                    String columnName = data.getColumnName(i);
                    if(i==count){
                        fields+= columnName;
                    }else{
                        fields+= columnName+",";
                    }
                }
                return fields;
            } catch (SQLException e) {
                e.printStackTrace();
            } catch (Exception e) {
                e.printStackTrace();
            }finally {
                JdbcUtil.close(resultSet, null,connection);
                if(proc!=null){
                    try {
                        proc.close();
                    } catch (SQLException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
        return null;
    }


    private String buildOrderSqlByConfig(QueryConfigVo queryConfigVo,String orderDdl) {
        if(StringUtil.isEmpty(orderDdl)){
            return queryConfigVo.getOrderBy()==null?"":queryConfigVo.getOrderBy();
        }
        if(StringUtil.isNotEmpty(queryConfigVo.getOrderBy()) ){
            String order = queryConfigVo.getOrderBy().toLowerCase();
            order = order.replace("order","");
            order = order.replace(" by","");
            return orderDdl+", "+order;
        }
        return orderDdl;
    }
    public String buildWhereSqlByConfig(QueryConfigVo queryConfigVo,JSONObject parameter) {
        String whereSql = "";
        if(StringUtil.isNotEmpty(queryConfigVo.getEditorFn())){
            whereSql = whereSql+queryConfigVo.getSqlByJquery(queryConfigVo.getEditorFn(),parameter,queryBuilderService);
        }else{
            if(StringUtil.isNotEmpty(queryConfigVo.getQueryFn())){
                whereSql = whereSql+queryConfigVo.getSqlByJquery(queryConfigVo.getQueryFn(),parameter,queryBuilderService);
            }
        }
        if(StringUtil.isNotEmpty(whereSql)){
            whereSql = " AND "+whereSql;
        }
        whereSql = whereSql+queryConfigVo.getBetweenSqlStr();
        return whereSql;
    }

    private JSONTreeNode buildParameterTree(Map<String,Object> map) {
        JSONTreeNode node = new JSONTreeNode();
        String parent = map.get("DATASOURCE_CODE").toString();
        String id  = JEUUID.uuid();
        node.setId(id);
        node.setParent(map.get("JE_CORE_DATASOURCE_ID").toString());
        node.setLeaf(false);
        node.setText("参数");
        node.setIcon("");
        node.setNodeType("GENERAL");
        node.setNodeInfoType("parameter");
        if(StringUtil.isNotEmpty(map.get("DATASOURCE_RESULT_CONFIG"))){
            JSONObject jsonObject = JSON.parseObject(map.get("DATASOURCE_RESULT_CONFIG").toString());
            if(jsonObject.containsKey("params")){
                JSONArray jsonArray = JSON.parseArray(jsonObject.getString("params"));
                for(int i =0;i<jsonArray.size();i++){
                    node.getChildren().add(buildParameterChild(parent,JEUUID.uuid(),jsonArray.getJSONObject(i)));
                }
            }
        }
        return node;
    }

    private JSONTreeNode buildParameterChild(String parentId,String id, JSONObject jsonObject) {
        JSONTreeNode node = new JSONTreeNode();
        node.setId(id);
        node.setParent(parentId);
        node.setLeaf(false);
        node.setText(jsonObject.getString("name"));
        node.setIcon("");
        node.setNodeType("LEAF");
        node.setNodeInfoType("parameterchild");
        return node;
    }

    private JSONTreeNode buildFieldTree(Map<String,Object> map) {
        JSONTreeNode node = new JSONTreeNode();
        String parent = map.get("DATASOURCE_CODE").toString();
        String id  = JEUUID.uuid();
        node.setId(id);
        node.setParent(map.get("JE_CORE_DATASOURCE_ID").toString());
        node.setLeaf(false);
        node.setText("字段");
        node.setIcon("");
        node.setNodeType("GENERAL");
        node.setNodeInfoType("field");
        if(StringUtil.isNotEmpty(map.get("DATASOURCE_RESULT_CONFIG"))){
            JSONObject jsonObject = JSON.parseObject(map.get("DATASOURCE_RESULT_CONFIG").toString());
            if(jsonObject.containsKey("fields")){
                String[] arr = jsonObject.getString("fields").split(",");
                for(int i =0;i<arr.length;i++){
                    node.getChildren().add(buildFieldChild(parent,JEUUID.uuid(),arr[i],map.get("JE_CORE_DATASOURCE_ID").toString()));
                }
            }
        }
        return node;
    }

    private JSONTreeNode buildFieldChild(String parentId, String id, String fieldName,String dataSourceId) {
        JSONTreeNode node = new JSONTreeNode();
        node.setId(id);
        node.setParent(parentId);
        node.setLeaf(false);
        node.setText(fieldName);
        node.setIcon("");
        node.setNodeType("LEAF");
        node.setNodeInfoType("fieldchild");
        Map<String,Object> map = new HashMap<>();
        map.put("JE_CORE_DATASOURCE_ID",dataSourceId);
        node.setBean(map);
        return node;
    }

    private JSONTreeNode buildDataSourceTree(List<DynaBean> dataSourceList) {
        JSONTreeNode rootNode = TreeUtil.buildRootNode();
        for(DynaBean dataSource:dataSourceList){
            JSONTreeNode node = buildDataSourceTreeNode(rootNode.getId(),dataSource);
            if (node != null) {
                rootNode.getChildren().add(node);
            }
        }
        return rootNode;
    }

    private JSONTreeNode buildDataSourceTreeNode(String id, DynaBean dataSource) {
        JSONTreeNode node = new JSONTreeNode();
        node.setId(dataSource.getPkValue());
        node.setParent(id);
        node.setLeaf(true);
        node.setText(dataSource.getStr("DATASOURCE_TEXT"));
        node.setCode(dataSource.getStr("DATASOURCE_CODE"));
        node.setIcon(dataSource.getStr("DATASOURCE_ICON"));
        node.setOrderIndex(dataSource.getStr("SY_ORDERINDEX"));
        node.setNodeInfo(dataSource.getStr("DATASOURCE_CODE"));
        node.setNodeType("GENERAL");
        node.setNodePath(dataSource.getStr("SY_PATH"));
        node.setDescription(dataSource.getStr("DATASOURCE_REMARK"));
        node.setNodeInfoType("DataSource");
        String type = dataSource.getStr("DATASOURCE_TYPE");
        Map<String,Object> map = new HashedMap();
        if("JS".equals(type)){
            map.put("script",dataSource.getStr("DATASOURCE_CONFIG"));
        }else if("VIEW".equals(type)){
            String script="";
            String config = dataSource.getStr("DATASOURCE_CONFIG");
            if(StringUtil.isNotEmpty(config)){
                JSONObject jsonObject = JSON.parseObject(config);
                script = jsonObject.getString("jsScript");
            }
            map.put("script",script);
        }
        map.put("DATASOURCE_CODE",dataSource.getStr("DATASOURCE_CODE"));
        map.put("DATASOURCE_TYPE",dataSource.getStr("DATASOURCE_TYPE"));
        map.put("JE_CORE_DATASOURCE_ID",dataSource.getStr("JE_CORE_DATASOURCE_ID"));
        map.put("DATASOURCE_RESULT_CONFIG",dataSource.getStr("DATASOURCE_RESULT_CONFIG"));
        node.setBean(dataSource.getValues());
        return node;
    }

}
